/*
 * ACR120UReader.java
 *
 */
package cn.com.zsc.acr120u;

import acs.jni.ACR120U;

import java.util.concurrent.locks.ReentrantLock;
import java.util.logging.Level;
import java.util.logging.Logger;

public class ACR120UReader {

	/** the the cardReader reference */
	private ACR120U cardReader;

	/** cardReader connection handle (result from opening the device) */
	private short handle = -1;

	/** last result message */
	private String message;

	/** default sector+block to write/read card */
	private byte blocknr = 8, sector = 2;

	public ReentrantLock locker;

	/**
	 * Open connection to the cardreader and keep the handle
	 */
	public void openReader() {
		handle = -1;
		try {
			cardReader = new ACR120U();
		} catch (java.lang.UnsatisfiedLinkError e) {
			e.printStackTrace();
			System.err.println("Are you sure the DLL is installed ?");
			message = "DLL Installation problem.";
			return;
		}
		handle = cardReader.open(ACR120U.ACR120_USB1);
		if (handle < 0) {
			message = "Error opening reader [port may be in use or reader not in binary mode]";
			System.err.println(message);
			return;
		}
		message = "Device opened. handle=" + handle;
	}

	/**
	 * check device must be opened
	 * 
	 * @return
	 */
	public boolean checkOpen() {
		if (handle < 0) {
			message = "Device not open";
			System.err.println(message);
			return false;
		}
		return true;
	}

	public static void Open_door() {
		ReentrantLock locker = new ReentrantLock();
		int open = 2;
		if (open == 2) {

			locker.lock();
			try {
				Thread.sleep(5000);
			} catch (InterruptedException ex) {
				Logger.getLogger(ACR120UReader.class.getName()).log(
						Level.SEVERE, null, ex);
			}
			locker.unlock();

		} else {
			locker.unlock();
		}
	}

	public long readSerialOnly() {
		byte[] pLen = new byte[1];
		byte[] pTAG = new byte[1];
		byte[] pSN = new byte[10];
		short tag = cardReader.select(handle, pTAG, pLen, pSN);
		if (tag < 0) {
			message = " NO TAG FOUND";
			return 0;
		} else {
			long serial = 0;
			for (int i = 0; i < pLen[0]; i++) {
				serial = (serial << 8);
				serial = serial | (pSN[i] & 0xFF); 
			}

			while (serial == 1687970147 && tag < 0) {
				readSerialOnly();
			}
			if (serial != 1687970147) {

				for (int buzzcounter = 0; buzzcounter <= 10; buzzcounter++) {
					buzzer(true);
					try {
						Thread.sleep(200);
					} catch (InterruptedException ex) {
						Logger.getLogger(ACR120UReader.class.getName()).log(
								Level.SEVERE, null, ex);
					}
					buzzer(false);
				}

				return 0;
			}

			return 0;
		}
	}

	/**
	 * Get CardID
	 * @return CardID
	 */
	public String getCardID()
	{
		if (!checkOpen()) {
			return null;
		}
		byte[] pLen = new byte[1];
		byte[] pTAG = new byte[1];
		byte[] pSN = new byte[10];
		short tag = cardReader.select(handle, pTAG, pLen, pSN);
		if (tag < 0) {
			message = " NO TAG FOUND";
			System.err.println(message);
			System.out.println("Deur gaat niet open (readTag())");
			return message;
		} else {
			System.out.println("Tagtype:" + pTAG[0] + " SN[0]:"
					+ Integer.toHexString(pSN[0]) + " return= " + tag);

			long serial = 0;
			for (int i = 0; i < pLen[0]; i++) {
				serial = (serial << 8); 
				serial = serial | (pSN[i] & 0xFF);
			}
			
			return String.valueOf(serial);
		}
	}
	
	@SuppressWarnings("SleepWhileHoldingLock")
	public long readTag() {
		if (!checkOpen()) {
			return 0;
		}
		byte[] pLen = new byte[1];
		byte[] pTAG = new byte[1];
		byte[] pSN = new byte[10];
		short tag = cardReader.select(handle, pTAG, pLen, pSN);
		if (tag < 0) {
			message = " NO TAG FOUND";
			System.err.println(message);
			System.out.println("Deur gaat niet open (readTag())");
			return 0;
		} else {
			System.out.println("Tagtype:" + pTAG[0] + " SN[0]:"
					+ Integer.toHexString(pSN[0]) + " return= " + tag);

			long serial = 0;
			for (int i = 0; i < pLen[0]; i++) {
				// shift and bitwise-OR the bytes into one 64-bits integer
				serial = (serial << 8); // shift left 8 bits
				serial = serial | (pSN[i] & 0xFF); // bitwise OR byte into int
			}
			System.out.printf(" serial = %d hex: %X", serial, serial);

			System.out.println();

			if (serial == 1687970147) {

				buzzer(true);
				try {
					Thread.sleep(200);
				} catch (InterruptedException ex) {
					Logger.getLogger(ACR120UReader.class.getName()).log(
							Level.SEVERE, null, ex);
				}
				buzzer(false);

				Open_door();
				for (;;) {
					readSerialOnly();

				}

			}

			else if (serial == 1414618723 & pTAG[0] == 2) {

				buzzer(true);
				try {
					Thread.sleep(200);
				} catch (InterruptedException ex) {
					Logger.getLogger(ACR120UReader.class.getName()).log(
							Level.SEVERE, null, ex);
				}
				buzzer(false);
				buzzer(true);
				try {
					Thread.sleep(50);
				} catch (InterruptedException ex) {
					Logger.getLogger(ACR120UReader.class.getName()).log(
							Level.SEVERE, null, ex);
				}
				buzzer(false);
				buzzer(true);
				try {
					Thread.sleep(200);
				} catch (InterruptedException ex) {
					Logger.getLogger(ACR120UReader.class.getName()).log(
							Level.SEVERE, null, ex);
				}
				buzzer(false);

				 Open_door();

			} 

			if (pTAG[0] != 2) {

				for (int buzzcounter = 0; buzzcounter <= 10; buzzcounter++) {
					buzzer(true);
					try {
						Thread.sleep(200);
					} catch (InterruptedException ex) {
						Logger.getLogger(ACR120UReader.class.getName()).log(
								Level.SEVERE, null, ex);
					}
					buzzer(false);
				}
			}

			message = "Tag read";
			return (int) serial;
		}
	}

	/**
	 * Reset the cardreader
	 */
	public void reset() {
		if (!checkOpen()) {
			return;
		}
		cardReader.power(handle, (byte) 1);
		cardReader.reset(handle);
		message = "device reset done";
	}

	/** buzzer does not work on serial ACR120S */
	public void buzzer(boolean status) {
		byte newSetting = 0;
		if (status) {
			newSetting = 0x44;
		} else {
			newSetting = 0; 
		}
		cardReader.writeUserPort(handle, newSetting);
	}

	/** power*/
	public void power(boolean power) {
		if (!checkOpen()) {
			return;
		}
		System.out.println("POWER " + power);
		if (power) {

			cardReader.power(handle, (byte) 1);
			cardReader.writeUserPort(handle, (byte) 0x05); // buzzer on
		} else {
			cardReader.writeUserPort(handle, (byte) 0x00);
			cardReader.power(handle, (byte) 0);
		}
	}

	/** get the last error or status message */
	public String getMessage() {
		return message;
	}

	/** close the reader device and COM port */
	void close() {
		if (!checkOpen()) {
			return;
		}
		cardReader.power(handle, (byte) 0);
		cardReader.close(handle);
		handle = -1;
		message = "Device closed";
	}

	/** write some data in a block */
	@SuppressWarnings("ManualArrayToCollectionCopy")
	public void writeString(String s) {
		if (!login()) {
			return;
		}
		s = s + "                "; // padding in case len < 16
		byte[] b = s.getBytes();
		byte[] b16 = new byte[16];
		for (int i = 0; i < 16; i++) {
			b16[i] = b[i];
		}
		int result = cardReader.write(handle, blocknr, b16);
		if (result < 0) {
			message = "write block failed";
		}
		System.err.println(message);
	}

	/** read som block data */
	public String readString() {
		if (!login()) {
			return "Login Error";
		}
		String s;
		byte[] bdata = new byte[16];
		cardReader.read(handle, blocknr, bdata);
		s = new String(bdata);
//		System.err.println("Read block: " + s);
		return s;
	}

	/** read som block data */
	public byte[] readBlock(int blocknr) {
		byte[] bdata = new byte[16];
		for (int i = 0; i < 16; i++) {
			bdata[i] = 0;
		}
		int result = cardReader.read(handle, (byte) blocknr, bdata);
		if (result < 0) {
			System.err.println("error reading block " + blocknr);
			return bdata;
		}
		System.err.printf("Page %02d: ", blocknr);
		for (int i = 0; i < 4; i++) {
			int b = bdata[i] & 0xFF;
			System.err.printf("%02X ", b);
		}
		System.err.println();
		return bdata;
	}

	/** login into a sector on a card */
	public boolean login() {
		byte keytype = (byte) ACR120U.AC_MIFARE_LOGIN_KEYTYPE_A;
		byte[] key = new byte[6];
		for (int i = 0; i < 6; i++) {
			key[i] = (byte) 0xff;
		}
		int result;
		byte[] pLen = new byte[1];
		byte[] pTAG = new byte[1];
		byte[] pSN = new byte[10];
		short tag = cardReader.select(handle, pTAG, pLen, pSN);
		
		if (tag==0){
		result = cardReader.login(handle, sector, keytype, (byte) 00, key);
		if (result < 0) {
			message = "login failed";

			System.out.println(message+">>>>"+result);
			return false;
		}
		return true;
		}
		return false;
	}

	public void blink() {
		boolean p = false;
		for (int i = 1; i <= 5; i++) {
			buzzer(p);
			p = !p;
			try {
				Thread.sleep(500);
			} catch (InterruptedException ex) {
				ex.printStackTrace();
			}
		}
	}
}